
package Zim::GUI::Calendar;

use strict;
use vars '$AUTOLOAD';
use POSIX qw(strftime);
use Gtk2::Gdk::Keysyms;
use Zim::GUI::Component;

our $VERSION = '0.18';
our @ISA = qw/Zim::GUI::Component/;

=head1 NAME

Zim::GUI::Calendar - Calendar widget for zim

=head1 DESCRIPTION

FIXME descriptve text

=head1 METHODS

=over 4

=item C<new(app => PARENT)>

Simple constructor.

=cut

my ($k_return, $k_kp_enter, $k_space, $k_escape)
	= @Gtk2::Gdk::Keysyms{qw/Return KP_Enter space Escape/};

sub init {
	my $self = shift;
	my $app = $self->{app};

	$app->{settings}{cal_namespace} = 
		$app->{repository}->resolve_page(
			$app->{settings}{cal_namespace} )->name;
	$app->{settings}{cal_namespace} =~ s/\:?$/:/;

	my $dialog = Gtk2::Dialog->new(
		'Calendar - Zim', $self->{app}{window},
	       	[qw/destroy-with-parent no-separator/],
	);
	$dialog->set_resizable(0);
	$dialog->signal_connect(delete_event => sub {
			$self->{app}{actions}->get_action('TCalendar')->set_active(0);
			return 1;
		} );
	$dialog->vbox->set_spacing(5);
	$self->{window} = $dialog;

	my $fmt = "%A %d %B %Y";
	my $label = Gtk2::Label->new(strftime($fmt, localtime));
	Glib::Timeout->add(60_000, sub {
			return 0 unless $dialog->visible;
			$label->set_text(strftime($fmt, localtime));
			return 1;
		} );
		# check once every minute whether the day didn't change
	$dialog->vbox->add($label);

	my $calendar = Gtk2::Calendar->new();
	$calendar->display_options (
		[qw/show-heading show-day-names show-week-numbers/] );
	$dialog->vbox->add($calendar);
	$self->{widget} = $calendar;

	$calendar->signal_connect(key_press_event => \&on_key_press_event, $self);
	$calendar->signal_connect(button_press_event => \&on_button_press_event, $self);
	$calendar->signal_connect(day_selected => \&on_day_selected_tmp, $self);
	$calendar->signal_handlers_block_by_func(\&on_day_selected_tmp);
	$calendar->signal_connect(day_selected_double_click => \&on_day_selected, $self);
	$calendar->signal_connect(month_changed => \&on_month_changed, $app);
	
	$app->signal_connect('page_loaded' => \&on_page_loaded);

	my $hbox = Gtk2::HBox->new(0,0);
	$dialog->vbox->pack_start($hbox, 0,1,0);
	my $today_button = Gtk2::Button->new('_Today');
	$hbox->pack_end($today_button, 0,1,0);
	$today_button->signal_connect( clicked => sub {
		my ($day, $month, $year) = (localtime)[3,4,5];
		$year += 1900;
		$calendar->select_month($month, $year);
		$calendar->select_day($day);
	} );
}

sub on_key_press_event {
	my ($cal, $event, $self) = @_;
	my $val = $event->keyval;
	if ($val == $k_return or $val == $k_kp_enter) { # Enter
		# TODO trigger space keybinding on calendar widget
	}
	elsif ($val == $k_space) { # Space
		$cal->signal_handlers_unblock_by_func(\&on_day_selected_tmp);
	}
	elsif ($val == $k_escape) {
		$self->{app}{actions}->get_action('TCalendar')->set_active(0);
		return 1;
	}
	return 0; 
}

sub on_button_press_event {
	my ($cal, $event, $self) = @_;
	return unless $event->type eq 'button-press';
	$cal->signal_handlers_unblock_by_func(\&on_day_selected_tmp)
		if $event->button == 1;
	return 0;
}

sub on_day_selected { $_[1]->{app}->load_date( reverse $_[0]->get_date ) }

sub on_day_selected_tmp {
	$_[0]->signal_handlers_block_by_func(\&on_day_selected_tmp);
	goto &on_day_selected;
}

sub on_month_changed {
	my ($cal, $app) = @_;
	$cal->clear_marks;
	
	my $nspace = $app->{settings}{cal_namespace};
	my ($year, $month, $day) = $cal->get_date;
	$year -= 1900;
	my $string = strftime('%Y_%m', 0, 0, 0, $day, $month, $year);
#	warn "Looking for $string in $nspace\n";
	for ($app->{repository}->list_pages($nspace)) {
#		warn "$_\n";
		/^$string\_(\d{2})/ or next;
		$cal->mark_day($1);
#		warn "Marked $1\n";
	}
}

sub on_page_loaded {
	my ($app, $page) = @_;
	my $cal = $app->Calendar;
	return unless $app->{settings}{show_cal};
	my $nspace = $app->{settings}{cal_namespace};
#	warn "Comparing $page wiht $nspace\n";
	$page =~ /^:*\Q$nspace\E:*(\d{4})_(\d{2})_(\d{2})/ or return;
	my ($day, $month, $year) = ($3, $2, $1);
	$month -= 1; # 0 based
	$cal->select_month($month, $year);
	$cal->select_day($day);
}

=item C<visible()>

Returns whether the calendar is visible.

=cut

sub visible { $_[0]->{window}->visible }

=item C<show()>

Show the calendar.

=cut

sub show {
	my $self = shift;
	my $w = $self->{window};
	$w->set_no_show_all(0);
	$w->move( @{$self->{position}} ) if $self->{position};
	$w->show_all;
	$w->move( @{$self->{position}} ) if $self->{position};
	&on_page_loaded($self->{app}, $self->{app}{page}->name);
	&on_month_changed($self->{widget}, $self->{app});
}

=item C<hide()>

Hide the calendar.

=cut

sub hide {
	my $self = shift;
	my $w = $self->{window};
	$self->{position} = [ $w->get_position ];
	$w->hide_all;
	$w->set_no_show_all(1);
}

1;

__END__

=back

=head1 AUTHOR

Jaap Karssenberg (Pardus) E<lt>pardus@cpan.orgE<gt>

Copyright (c) 2006 Jaap G Karssenberg. All rights reserved.
This program is free software; you can redistribute it and/or
modify it under the same terms as Perl itself.

=head1 SEE ALSO

=cut

